package com.lagou.rpc.provider.handler;

import com.alibaba.fastjson.JSON;
import com.lagou.rpc.common.RpcRequest;
import com.lagou.rpc.common.RpcResponse;
import com.lagou.rpc.provider.annotion.RpcService;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.springframework.beans.BeansException;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ChannelHandler.Sharable
public class NettyServerHandler extends SimpleChannelInboundHandler<String> implements ApplicationContextAware {

    private static final Map SERVICE_INSTANCE_MAP = new ConcurrentHashMap();

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
        RpcRequest request =  JSON.parseObject(msg, RpcRequest.class);
        RpcResponse rpcResponse = new RpcResponse();
        rpcResponse.setRequestId(request.getRequestId());

        try {
            rpcResponse.setResult(handler(request));
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            rpcResponse.setError(e.getMessage());
        }

        channelHandlerContext.writeAndFlush(JSON.toJSONString(rpcResponse));
    }

    @Override
    public void  setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(RpcService.class);
        if( beansWithAnnotation!=null && beansWithAnnotation.size()>0 ){
            Set<Map.Entry<String, Object>> entries = beansWithAnnotation.entrySet();
            for (Map.Entry<String, Object> item : entries){
                Object value = item.getValue();
                if(value.getClass().getInterfaces().length==0){
                    throw  new RuntimeException(value.getClass().getName()+":必须实现接口");
                }

                Class<?>[] interfaces = value.getClass().getInterfaces();
                SERVICE_INSTANCE_MAP.put(interfaces[0].getName(),value);
            }
        }

    }

    public Object handler(RpcRequest rpcRequest) throws InvocationTargetException {
        String className = rpcRequest.getClassName();
        if(SERVICE_INSTANCE_MAP.get(className) == null){
            throw new RuntimeException("根据beanName找不到服务,beanName:" + className);
        }

        Object o = SERVICE_INSTANCE_MAP.get(className);
        String methodName = rpcRequest.getMethodName();
        Object[] parameters = rpcRequest.getParameters();
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();

        //利用反射 调用方法
        FastClass fastClass = FastClass.create(o.getClass());

        FastMethod method = fastClass.getMethod(methodName, parameterTypes);
        Object invoke = method.invoke(o, parameters);

        return invoke;

    }
}
